//
//  UIControl+LYExtension.m
//  即时通讯
//
//  Created by 林域 on 2018/12/6.
//  Copyright © 2018 林域. All rights reserved.
//

#import "UIControl+LYExtension.h"
#import <objc/runtime.h>
#import <AVFoundation/AVFoundation.h>


#define LY_UICONTROL_EVENT(methodName, eventName)                                \
-(void)methodName : (void (^)(void))eventBlock {                              \
objc_setAssociatedObject(self, @selector(methodName:), eventBlock, OBJC_ASSOCIATION_COPY_NONATOMIC);\
[self addTarget:self                                                        \
action:@selector(methodName##Action:)                                       \
forControlEvents:UIControlEvent##eventName];                                \
}                                                                               \
-(void)methodName##Action:(id)sender {                                        \
void (^block)(void) = objc_getAssociatedObject(self, @selector(methodName:));  \
if (block) {                                                                \
block();                                                                \
}                                                                           \
}
static char const * const ly_kSoundsKey = "ly_kSoundsKey";

@implementation UIControl (LYExtension)

- (void)ly_setSoundNamed:(NSString *)name forControlEvent:(UIControlEvents)controlEvent
{
    // Remove the old UI sound.
    NSString *oldSoundKey = [NSString stringWithFormat:@"%zd", controlEvent];
    AVAudioPlayer *oldSound = [self ly_sounds][oldSoundKey];
    [self removeTarget:oldSound action:@selector(play) forControlEvents:controlEvent];
    
    // Set appropriate category for UI sounds.
    // Do not mute other playing audio.
    [[AVAudioSession sharedInstance] setCategory:@"AVAudioSessionCategoryAmbient" error:nil];
    
    // Find the sound file.
    NSString *file = [name stringByDeletingPathExtension];
    NSString *extension = [name pathExtension];
    NSURL *soundFileURL = [[NSBundle mainBundle] URLForResource:file withExtension:extension];
    
    NSError *error = nil;
    
    // Create and prepare the sound.
    AVAudioPlayer *tapSound = [[AVAudioPlayer alloc] initWithContentsOfURL:soundFileURL error:&error];
    NSString *controlEventKey = [NSString stringWithFormat:@"%zd", controlEvent];
    NSMutableDictionary *sounds = [self ly_sounds];
    [sounds setObject:tapSound forKey:controlEventKey];
    [tapSound prepareToPlay];
    if (!tapSound) {
        NSLog(@"Couldn't add sound - error: %@", error);
        return;
    }
    
    // Play the sound for the control event.
    [self addTarget:tapSound action:@selector(play) forControlEvents:controlEvent];
}


#pragma mark - Associated objects setters/getters

- (void)setly_sounds:(NSMutableDictionary *)sounds
{
    objc_setAssociatedObject(self, ly_kSoundsKey, sounds, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}

- (NSMutableDictionary *)ly_sounds
{
    NSMutableDictionary *sounds = objc_getAssociatedObject(self, ly_kSoundsKey);
    
    // If sounds is not yet created, create it.
    if (!sounds) {
        sounds = [[NSMutableDictionary alloc] initWithCapacity:2];
        // Save it for later.
        [self setly_sounds:sounds];
    }
    return sounds;
}


#pragma mark - Interactive Block -

LY_UICONTROL_EVENT(ly_touchDown, TouchDown)
LY_UICONTROL_EVENT(ly_touchDownRepeat, TouchDownRepeat)
LY_UICONTROL_EVENT(ly_touchDragInside, TouchDragInside)
LY_UICONTROL_EVENT(ly_touchDragOutside, TouchDragOutside)
LY_UICONTROL_EVENT(ly_touchDragEnter, TouchDragEnter)
LY_UICONTROL_EVENT(ly_touchDragExit, TouchDragExit)
LY_UICONTROL_EVENT(ly_touchUpInside, TouchUpInside)
LY_UICONTROL_EVENT(ly_touchUpOutside, TouchUpOutside)
LY_UICONTROL_EVENT(ly_touchCancel, TouchCancel)
LY_UICONTROL_EVENT(ly_valueChanged, ValueChanged)
LY_UICONTROL_EVENT(ly_editingDidBegin, EditingDidBegin)
LY_UICONTROL_EVENT(ly_editingChanged, EditingChanged)
LY_UICONTROL_EVENT(ly_editingDidEnd, EditingDidEnd)
LY_UICONTROL_EVENT(ly_editingDidEndOnExit, EditingDidEndOnExit)


@end
